package org.iabako.server.tools;

import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.iabako.server.serviceimpl.security.SessionUser;
import org.iabako.server.tools.pdftable.PdfCell;
import org.iabako.server.tools.pdftable.PdfRow;
import org.iabako.server.tools.pdftable.PdfTable;
import org.iabako.server.tools.pdftable.PdfWriterHelper;
import org.iabako.shared.entity.business.Installment;
import org.iabako.shared.entity.business.Payment;
import org.iabako.shared.entity.business.Sale;
import org.iabako.shared.entity.business.SaleProductService;
import org.iabako.shared.entity.enumeration.Language;
import org.iabako.shared.entity.enumeration.PriceUnit;
import org.iabako.shared.querydefinition.columndefinition.InstallmentColumnEnum;
import org.iabako.shared.querydefinition.columndefinition.PaymentColumnEnum;
import org.iabako.shared.querydefinition.columndefinition.ProductColumnEnum;
import org.iabako.shared.tools.GenericTools;
import org.springframework.beans.factory.annotation.Autowired;

import java.awt.*;
import java.io.IOException;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by jose on 05/02/15.
 */
@org.springframework.stereotype.Component
public class PdfInvoiceTableHelper {

    @Autowired
    protected BundleMessages messages;
    @Autowired
    SessionUser sessionUser;

    public PdfTable addProductServiceTable(PdfWriterHelper pdfWriterHelper,
                                           PdfInvoiceTableDescriptor tableDescriptor) throws IOException {

        List<SaleProductService> productServiceList = tableDescriptor.getProductServices();
        Language language = sessionUser.getUser().getEnterprise().getLanguage();

        addTitle(pdfWriterHelper, tableDescriptor.getTitle());
        PdfTable productServiceInfo = getSaleTableWithHeader(pdfWriterHelper, tableDescriptor);

        Map<String, Integer> headers = getHeaders(tableDescriptor);

        int index = 0;
        for (SaleProductService saleProductService : productServiceList) {
            String number = saleProductService.getProduct() != null ? saleProductService.getProduct().getNumber() : saleProductService.getService().getNumber();
            number = number.length() > 7 ? number.substring(0, 7) + "\n" + number.substring(7) : number;
            String name = saleProductService.getProduct() != null ? saleProductService.getProduct().getName() : saleProductService.getService().getName();
            String description = saleProductService.getProduct() != null ? saleProductService.getProduct().getDescription() : saleProductService.getService().getDescription();

            Color backgroundColor = index++ % 2 == 0 ? Color.WHITE : PdfWriterHelper.gray;

            PdfRow headerRow = new PdfRow(15f);
            headerRow.setNoLine(true);

            PdfCell cell = new PdfCell(headers.get(ProductColumnEnum.number.getLabelKey()), number);
            formatCell(cell, backgroundColor);
            cell.setFontSize(7);
            cell.setRightAlign(false);
            headerRow.addCell(cell);

            cell = new PdfCell(headers.get("sale_make_product_or_service_title"),
                    name + "\n_small_text_" + messages.getLabel("product_form_description") + " : " + description);
            formatCell(cell, backgroundColor);
            cell.setRightAlign(false);
            cell.setFontSize(9);
            headerRow.addCell(cell);

            String quantityString = new Double(saleProductService.getQuantity()).intValue() + "";
            quantityString = saleProductService.getQuantity() == 0d
                    || saleProductService.getQuantity() / new Double(saleProductService.getQuantity()).intValue() == 1
                    ? quantityString
                    : ServerTools.formatAmount(language, saleProductService.getQuantity());

            if (saleProductService.getPriceUnit() != null && saleProductService.getPriceUnit() != PriceUnit.unit) {
                quantityString += " " + messages.getLabel(language, saleProductService.getPriceUnit().getLabelKey());
            }
            cell = new PdfCell(headers.get("sale_make_quantity_title"), quantityString);
            formatCell(cell, backgroundColor);
            headerRow.addCell(cell);

            cell = new PdfCell(headers.get("invoice_unit_price"), ServerTools.formatAmount(language, saleProductService.getPrice()));
            formatCell(cell, backgroundColor);
            headerRow.addCell(cell);

            Double total = saleProductService.getQuantity() * saleProductService.getPrice();
            Double taxPercent = saleProductService.getTaxPercent();

            if (tableDescriptor.isWithDifferentTaxes()) {
                cell = new PdfCell(headers.get("invoice_tax_percent"),
                        taxPercent != null ? ServerTools.formatAmount(language, taxPercent) : "-");
                formatCell(cell, backgroundColor);
                headerRow.addCell(cell);
            }

            if (tableDescriptor.isWithTaxes()) {
                taxPercent = taxPercent == null ? 0 : taxPercent;
                cell = new PdfCell(headers.get("invoice_total_before_tax"), ServerTools.formatAmount(language, total * (1 - taxPercent / 100)));
                formatCell(cell, backgroundColor);
                headerRow.addCell(cell);
            }

            cell = new PdfCell(tableDescriptor.isWithTaxes() ? headers.get("invoice_total_after_tax") : headers.get("invoice_total"),
                    ServerTools.formatAmount(language, total));
            formatCell(cell, backgroundColor);
            headerRow.addCell(cell);

            productServiceInfo.drawRow(headerRow);
            productServiceInfo = pdfWriterHelper.moveTopPointer(productServiceInfo, pdfWriterHelper.top - productServiceInfo.getNextYpos());
        }
        productServiceInfo.endTable();

        return productServiceInfo;
    }

    private void formatCell(PdfCell cell, Color backgroundColor) {
        cell.setNoLine(false);
        cell.setRightAlign(true);
        cell.setFont(PDType1Font.HELVETICA);
        cell.setFillColor(backgroundColor);
        cell.setTextColor(Color.DARK_GRAY);
    }

    private PdfTable getSaleTableWithHeader(PdfWriterHelper pdfWriterHelper, PdfInvoiceTableDescriptor tableDescriptor) throws IOException {

        pdfWriterHelper.margin = pdfWriterHelper.initMargin;
        PdfTable productServiceInfo = new PdfTable(pdfWriterHelper);
        productServiceInfo.setLineColor(Color.DARK_GRAY);
        productServiceInfo.setLineWidth(0);

        Map<String, Integer> headers = getHeaders(tableDescriptor);

        PdfRow headerRow = new PdfRow(15f);
        headerRow.setNoLine(true);
        for (String headerString : headers.keySet()) {
            PdfCell cell = new PdfCell(headers.get(headerString), messages.getLabel(headerString));
            cell.setNoLine(true);
            cell.setFont(PDType1Font.HELVETICA);
            cell.setFillColor(Color.GRAY);
            cell.setTextColor(Color.WHITE);
            if (!headerString.contains("number") && !headerString.contains("title")) {
                cell.setRightAlign(true);
            }
            headerRow.addCell(cell);
        }
        productServiceInfo.drawRow(headerRow);
        pdfWriterHelper.moveTopPointer(pdfWriterHelper.top - productServiceInfo.getNextYpos());
        return productServiceInfo;
    }

    private Map<String, Integer> getHeaders(PdfInvoiceTableDescriptor tableDescriptor) {
        Map<String, Integer> headers = new LinkedHashMap<String, Integer>();

        headers.put(ProductColumnEnum.number.getLabelKey(), 40);
        headers.put("sale_make_product_or_service_title", 322);
        headers.put("sale_make_quantity_title", 50);
        headers.put("invoice_unit_price", 80);
        if (tableDescriptor.isWithDifferentTaxes()) {
            headers.put("sale_make_product_or_service_title", 192);
            headers.put("invoice_tax_percent", 50);
        }
        if (tableDescriptor.isWithTaxes()) {
            if (!tableDescriptor.isWithDifferentTaxes()) {
                headers.put("sale_make_product_or_service_title", 242);
            }
            headers.put("invoice_total_before_tax", 80);
            headers.put("invoice_total_after_tax", 80);
        } else {
            headers.put("invoice_total", 80);
        }

        return headers;
    }

    public PdfTable addPaymentTable(PdfWriterHelper pdfWriterHelper, PdfInvoiceTableDescriptor tableDescriptor) throws IOException {
        List<Payment> paymentList = tableDescriptor.getPayments();
        List<Installment> installmentList = tableDescriptor.getInstallments();
        if (paymentList == null && installmentList == null) {
            return null;
        }

        addTitle(pdfWriterHelper, tableDescriptor.getTitle());
        PdfTable paymentTable = getPaymentTableWithHeader(pdfWriterHelper, installmentList != null);

        if (paymentList != null) {
            addPaymentLines(pdfWriterHelper, paymentTable, paymentList);
        } else {
            addInstallmentLines(pdfWriterHelper, paymentTable, installmentList);
        }
        paymentTable.endTable();

        return paymentTable;
    }

    private void addInstallmentLines(PdfWriterHelper pdfWriterHelper, PdfTable paymentTable, List<Installment> installmentList) throws IOException {
        ServerTools serverTools = new ServerTools();

        Language language = sessionUser.getUser().getEnterprise().getLanguage();
        Map<String, Integer> headers = getPaymentInstallmentHeaders(true);

        int index = 0;
        for (Installment installment : installmentList) {

            String installmentDate = GenericTools.formatDate(installment.getDate());
            String amount = ServerTools.formatAmount(language, installment.getAmount());

            Color backgroundColor = index++ % 2 == 0 ? Color.WHITE : PdfWriterHelper.gray;

            PdfRow headerRow = new PdfRow(15f);
            headerRow.setNoLine(true);
            PdfCell cell = new PdfCell(headers.get("installment_status"),
                    serverTools.resetTime(installment.getDate()).compareTo(serverTools.resetTime(new Date())) <= 0 ?
                            messages.getLabel("installment_past_icon") : messages.getLabel("installment_future_icon"));
            formatCell(cell, backgroundColor);
            cell.setRightAlign(false);
            cell.setNoLine(true);
            headerRow.addCell(cell);
            cell = new PdfCell(headers.get(InstallmentColumnEnum.date.getLabelKey()), installmentDate);
            formatCell(cell, backgroundColor);
            cell.setRightAlign(false);
            cell.setNoLine(true);
            headerRow.addCell(cell);
            cell = new PdfCell(headers.get(PaymentColumnEnum.amount.getLabelKey()), amount);
            formatCell(cell, backgroundColor);
            cell.setNoLine(true);
            headerRow.addCell(cell);
            paymentTable.drawRow(headerRow);
            paymentTable = pdfWriterHelper.moveTopPointer(paymentTable, pdfWriterHelper.top - paymentTable.getNextYpos());
        }
    }

    private void addPaymentLines(PdfWriterHelper pdfWriterHelper, PdfTable paymentTable, List<Payment> paymentList) throws IOException {
        Language language = sessionUser.getUser().getEnterprise().getLanguage();
        Map<String, Integer> headers = getPaymentInstallmentHeaders(false);

        int index = 0;
        for (Payment payment : paymentList) {

            String scheduleDate = GenericTools.formatDate(payment.getScheduleDate());
            String paymentDate = GenericTools.formatDate(payment.getDate());
            String method = payment.getPaymentMethod() != null ? messages.getLabel(payment.getPaymentMethod().getLabelKey()) : "";
            String amount = ServerTools.formatAmount(language, payment.getAmount());

            Color backgroundColor = index++ % 2 == 0 ? Color.WHITE : PdfWriterHelper.gray;

            PdfRow headerRow = new PdfRow(15f);
            headerRow.setNoLine(true);
            PdfCell cell = new PdfCell(headers.get(PaymentColumnEnum.scheduleDate.getLabelKey()),
                    GenericTools.isEmpty(scheduleDate) ? "-" : scheduleDate);
            formatCell(cell, backgroundColor);
            cell.setRightAlign(false);
            cell.setNoLine(true);
            headerRow.addCell(cell);
            cell = new PdfCell(headers.get(PaymentColumnEnum.date.getLabelKey()), paymentDate);
            formatCell(cell, backgroundColor);
            cell.setRightAlign(false);
            cell.setNoLine(true);
            headerRow.addCell(cell);
            cell = new PdfCell(headers.get(PaymentColumnEnum.paymentMethod.getLabelKey()), method);
            formatCell(cell, backgroundColor);
            cell.setRightAlign(false);
            cell.setNoLine(true);
            headerRow.addCell(cell);
            cell = new PdfCell(headers.get(PaymentColumnEnum.amount.getLabelKey()), amount);
            formatCell(cell, backgroundColor);
            cell.setNoLine(true);
            headerRow.addCell(cell);
            paymentTable.drawRow(headerRow);
            paymentTable = pdfWriterHelper.moveTopPointer(paymentTable, pdfWriterHelper.top - paymentTable.getNextYpos());
        }
    }

    private Map<String, Integer> getPaymentInstallmentHeaders(boolean isInstallment) {
        Map<String, Integer> headers = new LinkedHashMap<String, Integer>();

        if (!isInstallment) {
            headers.put(PaymentColumnEnum.scheduleDate.getLabelKey(), 143);
        } else {
            headers.put("installment_status", 290);
        }
        if (isInstallment) {
            headers.put(InstallmentColumnEnum.date.getLabelKey(), isInstallment ? 140 : 143);
        } else {
            headers.put(PaymentColumnEnum.date.getLabelKey(), isInstallment ? 140 : 143);
        }
        if (!isInstallment) {
            headers.put(PaymentColumnEnum.paymentMethod.getLabelKey(), 143);
        }
        headers.put(PaymentColumnEnum.amount.getLabelKey(), isInstallment ? 142 : 143);

        return headers;
    }

    private PdfTable getPaymentTableWithHeader(PdfWriterHelper pdfWriterHelper, boolean isInstallment) throws IOException {
        Map<String, Integer> headers = getPaymentInstallmentHeaders(isInstallment);
        pdfWriterHelper.margin = pdfWriterHelper.initMargin;
        PdfTable paymentInfo = new PdfTable(pdfWriterHelper);
        paymentInfo.setLineColor(Color.GRAY);
        paymentInfo.setLineWidth(0);

        PdfRow headerRow = new PdfRow(15f);

        for (String header : headers.keySet()) {
            headerRow.setNoLine(true);
            PdfCell cell = new PdfCell(headers.get(header), messages.getLabel(header));
            cell.setNoLine(true);
            cell.setFont(PDType1Font.HELVETICA);
            cell.setFillColor(Color.GRAY);
            cell.setTextColor(Color.WHITE);
            if (header.contains("amount")) {
                cell.setRightAlign(true);
            }
            headerRow.addCell(cell);
        }

        paymentInfo.drawRow(headerRow);
        pdfWriterHelper.moveTopPointer(pdfWriterHelper.top - paymentInfo.getNextYpos());
        return paymentInfo;
    }

    private void addTitle(PdfWriterHelper pdfWriterHelper, String title) throws IOException {
        pdfWriterHelper.margin = pdfWriterHelper.initMargin;
        PdfTable productServiceTitle = new PdfTable(pdfWriterHelper);

        productServiceTitle.setLineColor(Color.WHITE);
        productServiceTitle.setLineWidth(0);
        float tableWidth = 300;
        PdfRow headerRow = new PdfRow(25f);
        PdfCell cell = new PdfCell(tableWidth, title);
        cell.setFontSize(10);
        cell.setFont(PDType1Font.HELVETICA);
        cell.setFillColor(Color.WHITE);
        cell.setTextColor(Color.DARK_GRAY);
        headerRow.addCell(cell);
        productServiceTitle.drawRow(headerRow);
        pdfWriterHelper.moveTopPointer(pdfWriterHelper.top - productServiceTitle.getNextYpos());
        productServiceTitle.endTable();
    }

    public void addTotal(PdfWriterHelper pdfWriterHelper, Sale sale, List<Payment> paymentList, List<Installment> installmentList, boolean saleTable) throws IOException {
        double salePrice = 0d;
        double salePriceRecalculated = 0d;
        double paymentPrice = 0d;
        double installmentPrice = 0d;

        if (saleTable) {
            salePrice = ServerTools.round(sale.calculateAmountFromProductsServices());
        }
        if (paymentList != null) {
            for (Payment payment : paymentList) {
                paymentPrice += payment.getAmount();
            }
        }
        if (installmentList != null) {
            for (Installment installment : installmentList) {
                installmentPrice += installment.getAmount();
            }
        }

        if (salePrice != paymentPrice + installmentPrice) {
            salePriceRecalculated = paymentPrice + installmentPrice;
        }

        boolean isProductServiceWithTax = sale.isProductServiceWithTax();
        boolean isProductServiceWithDifferentTaxes = sale.isProductServiceWithDifferentTaxes();
        double salePonderedTaxPercent = sale.getTaxPercent();

        if (saleTable) {
            drawTotalLines(pdfWriterHelper, isProductServiceWithTax, isProductServiceWithDifferentTaxes, false, salePonderedTaxPercent, salePrice);
            if (salePriceRecalculated > 0) {
                addRecalculationAlert(pdfWriterHelper);
                drawTotalLines(pdfWriterHelper, isProductServiceWithTax, isProductServiceWithDifferentTaxes, true, salePonderedTaxPercent, salePriceRecalculated);
            }
        } else if (paymentList != null) {
            drawTotalLines(pdfWriterHelper, isProductServiceWithTax, isProductServiceWithDifferentTaxes, false, salePonderedTaxPercent, paymentPrice);
        } else {
            drawTotalLines(pdfWriterHelper, isProductServiceWithTax, isProductServiceWithDifferentTaxes, false, salePonderedTaxPercent, installmentPrice);
        }
    }

    private void drawTotalLines(PdfWriterHelper pdfWriterHelper, boolean isProductServiceWithTax, boolean isProductServiceWithDifferentTaxes,
                                boolean isRecalculatedTotalLine, double salePonderedTaxPercent, double price) throws IOException {

        Language language = sessionUser.getUser().getEnterprise().getLanguage();

        String titleBeforeTax = isRecalculatedTotalLine ? messages.getLabel("invoice_recalculated_total_before_tax") : messages.getLabel("invoice_total_before_tax");
        titleBeforeTax += language == Language.FR ? " (EUR) : " : " : ";
        String titleAfterTax = isRecalculatedTotalLine ? messages.getLabel("invoice_recalculated_total_after_tax") : messages.getLabel("invoice_total_after_tax");
        titleAfterTax += language == Language.FR ? " (EUR) : " : " : ";
        String titleWithFixTax = isRecalculatedTotalLine ?
                messages.getLabel("invoice_recalculated_total_with_fixed_tax", ServerTools.formatAmount(language, salePonderedTaxPercent))
                : messages.getLabel("invoice_total_with_fixed_tax", ServerTools.formatAmount(language, salePonderedTaxPercent));
        titleWithFixTax += language == Language.FR ? " (EUR) : " : " : ";
        String simpleTitle = isRecalculatedTotalLine ? messages.getLabel("invoice_recalculated_total") : messages.getLabel("invoice_total");
        simpleTitle += language == Language.FR ? " (EUR) : " : " : ";

        if (isProductServiceWithTax) {
            drawTotal(pdfWriterHelper, titleBeforeTax, price * (1 - salePonderedTaxPercent / 100), true);
            String title = isProductServiceWithDifferentTaxes ? titleAfterTax : titleWithFixTax;
            drawTotal(pdfWriterHelper, title, price, false);
        } else {
            drawTotal(pdfWriterHelper, simpleTitle, price, false);
        }
    }

    private void addRecalculationAlert(PdfWriterHelper pdfWriterHelper) throws IOException {
        PdfTable invoiceInfo = new PdfTable(pdfWriterHelper);
        invoiceInfo.setLineColor(Color.WHITE);
        invoiceInfo.setLineWidth(0);
        PdfRow headerRow = new PdfRow(15f);

        PdfCell cell = new PdfCell(pdfWriterHelper.getPageContentWidth(), messages.getLabel("invoice_total_recalculation_note"));
        cell.setRightAlign(true);
        cell.setFontSize(8);
        cell.setFont(PDType1Font.HELVETICA);
        cell.setFillColor(Color.WHITE);
        cell.setTextColor(Color.DARK_GRAY);
        headerRow.addCell(cell);
        invoiceInfo.drawRow(headerRow);
        pdfWriterHelper.moveTopPointer(pdfWriterHelper.top - invoiceInfo.getNextYpos());
        invoiceInfo.endTable();
    }

    private void drawTotal(PdfWriterHelper pdfWriterHelper, String title, double salePrice, boolean small) throws IOException {
        Language language = sessionUser.getUser().getEnterprise().getLanguage();

        PdfTable invoiceInfo = new PdfTable(pdfWriterHelper);
        invoiceInfo.setLineColor(Color.WHITE);
        invoiceInfo.setLineWidth(0);
        PdfRow headerRow = new PdfRow(15f);

        PdfCell cell = new PdfCell(pdfWriterHelper.getPageContentWidth(), title + " " + ServerTools.formatAmount(language, salePrice));
        cell.setRightAlign(true);
        cell.setFontSize(small ? 8 : 10);
        cell.setFont(small ? PDType1Font.HELVETICA : PDType1Font.HELVETICA_BOLD);
        cell.setFillColor(Color.WHITE);
        cell.setTextColor(Color.DARK_GRAY);
        headerRow.addCell(cell);
        invoiceInfo.drawRow(headerRow);
        pdfWriterHelper.moveTopPointer(pdfWriterHelper.top - invoiceInfo.getNextYpos());
        invoiceInfo.endTable();
    }

}
